#include <iostream>
#include <pthread.h>
#include <queue>
#define NUM 5
template<class T>
class ThreadPool
{
private:
  std::queue<T> q;
  pthread_mutex_t lock;
  pthread_cond_t cond;
  int tnum;
 //接口封装 
 void unlock_queue()
 {
    pthread_mutex_unlock(&lock);
 }
 void lock_queue()
 {
   pthread_mutex_lock(&lock);
 }
 void wait()
 {
   pthread_cond_wait(&cond,&lock);
 }
 void wake_up()
 {
   pthread_cond_signal(&cond);
 }

 bool isqueue_empty()
 {
   return q.empty();
 }
  
  
  
public:
  ThreadPool(int _tnum=NUM):tnum(_tnum)
  {
    pthread_cond_init(&cond,nullptr);
    pthread_mutex_init(&lock,nullptr);
  }

//注意这里必须用static，否则this指针会隐藏传进来，表面上是一个参数，实际是两个参数，回调时候会出错
 static void* rounite(void* arg)
 {

  auto self=((ThreadPool*)arg);
  pthread_detach(pthread_self());
  while(1)
  {
    self->lock_queue();
    while(self->isqueue_empty())
    {
      self->wait();
    }
    //传进来的是任务，下面要处理任务
    T t;
    self->pop(t);
    self->unlock_queue();
    t.run();
    
  }
 }
  
 void thread_poll_init()
  {
    pthread_t tid;
    //创建几个线程，因为要满足回调函数，rountine设成了static，为了让它找到对象，要手动传this指针作为参数
    for(int i=0;i<tnum;i++)
    {
      pthread_create(&tid,nullptr,rounite,(void*)this);
      
    }
  }

 //只对外提供这一个接口，用户可以通过push把任务传进来
  void push(const T& in) 
  {
   lock_queue();
   q.push(in); 
   unlock_queue();
   wake_up();
  }

  void pop(T& out)
  {
    out=q.front();
    q.pop();
  }

  ~ThreadPool()
  {
    pthread_mutex_destroy(&lock);
    pthread_cond_destroy(&cond);
  }
};
